package cn.sylinx.web.template.velocity;

import java.io.IOException;
import java.io.StringWriter;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.context.Context;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;

import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.templ.impl.CachingTemplateEngine;

public class VelocityTemplateEngineImpl extends CachingTemplateEngine<Template> implements VelocityTemplateEngine {

	private VelocityEngine ve = null;

	public VelocityTemplateEngineImpl() {
		super(DEFAULT_TEMPLATE_EXTENSION, DEFAULT_MAX_CACHE_SIZE);
		ve = new VelocityEngine();
		ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
		ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
		ve.setProperty(RuntimeConstants.INPUT_ENCODING, "UTF-8");
		ve.setProperty(RuntimeConstants.OUTPUT_ENCODING, "UTF-8");
		ve.init();
	}

	@Override
	public void render(RoutingContext context, String templateFileName, Handler<AsyncResult<Buffer>> handler) {
		try {

			Template template = getTemplate(templateFileName);
			VelocityContext ctx = new VelocityContext();
			ctx.put("context", context);
			String rst = mergeTemplate(template, ctx);
			handler.handle(Future.succeededFuture(Buffer.buffer(rst)));

		} catch (Exception ex) {
			handler.handle(Future.failedFuture(ex));
		}
	}

	protected String mergeTemplate(Template template, Context context) {

		String rst = "";

		try (StringWriter sw = new StringWriter()) {

			template.merge(context, sw);
			rst = sw.toString();

		} catch (IOException e) {
		}

		return rst;
	}

	protected Template getTemplate(String templateFileName) {
		Template template = cache.get(templateFileName);
		if (template == null) {
			// real compile
			synchronized (this) {
				// Compile
				template = ve.getTemplate(adjustLocation(templateFileName));
			}
			cache.put(templateFileName, template);
		}
		return template;
	}

	@Override
	public VelocityTemplateEngine setExtension(String extension) {
		doSetExtension(extension);
		return this;
	}

	@Override
	public VelocityTemplateEngine setMaxCacheSize(int maxCacheSize) {
		this.cache.setMaxSize(maxCacheSize);
		return this;
	}

}
